home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
SGI Developer Toolbox 6.1
/
SGI Developer Toolbox 6.1 - Disc 4.iso
/
public
/
plan
/
src
/
lock.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-08-01
|
7KB
|
273 lines
/*
* read the master list from the ~/.schedule file. This file is also
* linked into the daemon program (file_w.c is not).
*
* resolve_tilde(path) return path with ~ replaced with home
* directory as found in $HOME
* find_file(buf, name,exec) find file <name> and store the path
* in <buf>. Return FALSE if not found.
* startup_lock(fname, force) make sure program runs only once
* at any time
* lockfile(fp, lock) lock or unlock the database to
* prevent simultaneous access
*/
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#if defined(IBM) || defined(ULTRIX)
#include <fcntl.h>
#else
#include <sys/fcntl.h>
#endif
#include <pwd.h>
#ifndef MIPS
#include <stdlib.h>
#endif
#if !defined(NOLOCK) && defined(LOCKF) || defined(linux)
#include <sys/file.h>
#endif
#include <unistd.h>
#if !defined(NOLOCK) && defined(LOCKF)
#include <sys/file.h>
#endif
#if defined(IBM) && !defined(NOLOCK)
#include <sys/lockf.h>
#endif
#include <sys/signal.h>
#include "conf.h"
#ifdef MIPS
extern char *getenv();
extern struct passwd *getpwnam();
#endif
extern char *progname; /* argv[0] */
char lockpath[256]; /* lockfile path */
/*
* If <path> begins with a tilde, replace the tilde with $HOME. This is used
* for the database files, and the holiday file (see holiday.c).
*/
char *resolve_tilde(path)
char *path; /* path with ~ */
{
struct passwd *pw; /* for searching home dirs */
static char pathbuf[512]; /* path with ~ expanded */
char *p, *q; /* username copy pointers */
char *home = 0; /* home dir (if ~ in path) */
if (*path != '~')
return(path);
if (!path[1] || path[1] == '/') {
*pathbuf = 0;
if (!(home = getenv("HOME")))
home = getenv("home");
} else {
for (p=path+1, q=pathbuf; *p && *p != '/'; p++, q++)
*q = *p;
*q = 0;
if (pw = getpwnam(pathbuf))
home = pw->pw_dir;
}
if (!home) {
fprintf(stderr, "%s: can't evaluate ~%s in %s, using .\n",
progname, pathbuf, path);
home = ".";
}
sprintf(pathbuf, "%s/%s", home, path+1);
return(pathbuf);
}
/*
* locate a program or file, and return its complete path. This is used by
* the daemon to locate notifier and user programs, and by plan to locate
* pland and plan.help. Assume that <buf> has space for 1024 chars. PATH
* is a macro defined by the Makefile.
*/
#ifndef PATH
#define PATH 0
#endif
#define DEFAULTPATH "/usr/local/bin:/usr/local/lib:/bin:/usr/bin:/usr/sbin:/usr/ucb:/usr/bsd:/usr/bin/X11:."
BOOL find_file(buf, name, exec)
char *buf; /* buffer for returned path */
char *name; /* file name to locate */
BOOL exec; /* must be executable? */
{
int method; /* search path counter */
char *path; /* $PATH or DEFAULTPATH */
int namelen; /* len of tail of name */
register char *p, *q; /* string copy pointers */
if (*name == '/') { /* begins with / */
strcpy(buf, name);
return(TRUE);
}
if (*name == '~') { /* begins with ~ */
strcpy(buf, resolve_tilde(name));
return(TRUE);
}
namelen = strlen(name);
for (method=0; ; method++) {
switch(method) {
case 0: path = PATH; break;
case 1: path = getenv("PLAN_PATH"); break;
case 2: path = getenv("PATH"); break;
case 3: path = DEFAULTPATH; break;
default: return(FALSE);
}
if (!path)
continue;
do {
q = buf;
p = path;
while (*p && *p != ':' && q < buf + 1021 - namelen)
*q++ = *p++;
*q++ = '/';
strcpy(q, name);
if (!access(buf, exec ? X_OK : R_OK)) {
strcpy(q = buf + strlen(buf), "/..");
if (access(buf, X_OK)) {
*q = 0;
return(TRUE);
}
}
*buf = 0;
path = p+1;
} while (*p);
}
/*NOTREACHED*/
}
/*
* Make sure that the program is running only once, by creating a special
* lockfile that contains our pid. If such a lockfile already exists, see
* if the process that created it exists; if no, ignore it. If <force> is
* TRUE, try to kill it. Otherwise, return FALSE.
*/
BOOL startup_lock(pathtmp, force)
char *pathtmp; /* LOCK_PATH or PLAN_PATH */
BOOL force; /* kill competitor */
{
char buf[80]; /* lockfile contents */
int lockfd; /* lock/pid file */
PID_T pid; /* pid in lockfile */
int retry = 5; /* try to kill daemon 5 times*/
sprintf(lockpath, pathtmp, (int)getuid());
while ((lockfd = open(lockpath, O_WRONLY|O_EXCL|O_CREAT, 0644)) < 0) {
if ((lockfd = open(lockpath, O_RDONLY)) < 0) {
int err = errno;
fprintf(stderr, "%s: cannot open lockfile ", progname);
errno = err;
perror(lockpath);
_exit(1);
}
if (read(lockfd, buf, 10) < 5) {
int err = errno;
fprintf(stderr, "%s: cannot read lockfile ", progname);
errno = err;
perror(lockpath);
_exit(1);
}
buf[10] = 0;
pid = atoi(buf);
close(lockfd);
if (!retry--) {
fprintf(stderr,
"%s: failed to kill process %d owning lockfile %s",
progname, pid, lockpath);
_exit(1);
}
# ifndef NOKILL0
if (kill(pid, 0) && errno == ESRCH) {
if (unlink(lockpath) && errno != ENOENT) {
int err = errno;
fprintf(stderr, "%s: cannot unlink lockfile ",
progname);
errno = err;
perror(lockpath);
_exit(1);
}
continue;
}
# endif
if (!force)
return(FALSE);
(void)kill(pid, SIGINT);
sleep(1);
}
sprintf(buf, "%5d (pid of lockfile for %s, for user %d)\n",
(int)getpid(), progname, (int)getuid());
if (write(lockfd, buf, strlen(buf)) != strlen(buf)) {
int err = errno;
fprintf(stderr, "%s: cannot write lockfile ", progname);
errno = err;
perror(lockpath);
_exit(1);
}
close(lockfd);
return(TRUE);
}
/*
* try to lock or unlock the database file. There is actually little risk
* that two plan programs try to access simultaneously, unless someone adds
* an appointment graphically, and then another one on the command line
* within 10 seconds. If people add two at the same time, locking doesn't
* help at all. As a side effect, the file is rewound.
*/
static BOOL got_alarm;
static void (*old_alarm)();
/*ARGSUSED*/ static void alarmhand(sig)
{
got_alarm = TRUE;
signal(SIGALRM, old_alarm);
}
lockfile(fp, lock)
FILE *fp; /* file to lock */
BOOL lock; /* TRUE=lock, FALSE=unlock */
{
#ifndef NOLOCK
if (lock) {
got_alarm = FALSE;
old_alarm = signal(SIGALRM, alarmhand);
alarm(3);
(void)rewind(fp);
(void)lseek(fileno(fp), 0, 0);
#ifdef FLOCK
if (flock(fileno(fp), LOCK_EX | LOCK_NB) || got_alarm) {
#else
if (lockf(fileno(fp), F_LOCK, 0) || got_alarm) {
#endif
perror(progname);
fprintf(stderr,
"%s: failed to lock database after 3 seconds, accessing anyway\n", progname);
}
alarm(0);
} else {
(void)rewind(fp);
(void)lseek(fileno(fp), 0, 0);
#ifdef FLOCK
(void)flock(fileno(fp), LOCK_UN);
#else
(void)lockf(fileno(fp), F_ULOCK, 0);
#endif
return;
}
#endif /* NOLOCK */
}